﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.ComponentModel;
using System.IO;
using System.Security.Cryptography;
using System.Collections;

namespace ResourceManager
{
    /// <summary>
    /// 请求资源结果
    /// </summary>
    public class LoadResourceCompletedEventArgs : AsyncCompletedEventArgs
    {
        public LoadResourceCompletedEventArgs(Exception error, bool cancelled, object userState, string filename)
            : base(error, cancelled, userState)
        {
            ResourceName = filename;
        }

        /// <summary>
        /// 请求的资源在本地的完整路径
        /// </summary>
        public string ResourceName { get; private set; }
    }

    public class LoadResourceProgressChangedEventArgs : ProgressChangedEventArgs
    {
        public LoadResourceProgressChangedEventArgs(int progressPercentage, object userState, string filename)
            : base(progressPercentage, userState)
        {
            ResourceName = filename;
        }

        /// <summary>
        /// 请求的资源在本地的完整路径
        /// </summary>
        public string ResourceName { get; private set; }
    }

    /// <summary>
    /// 指定远端服务类型
    /// </summary>
    public enum RemoteType
    {
        /// <summary>HTTP</summary>
        HTTP,
        /// <summary>FTP</summary>
        FTP,
        /// <summary>DMZ</summary>
        DMZ,
        /// <summary>FILE</summary>
        FILE,
    }

    /// <summary>
    /// 资源提供服务
    /// </summary>
    public class Service
    {
        public Config Config
        {
            get { return _config; }
            set { _config = value; }
        }

        public const string VERSIONFILE_LOAD = "MICROEND_VERSIONFILE_LOAD";

        /// <summary>加载资源结果回调</summary>
        public event EventHandler<LoadResourceCompletedEventArgs> LoadResourceCompleted = delegate { };

        /// <summary>加载资源过程回调</summary>
        public event EventHandler<LoadResourceProgressChangedEventArgs> LoadProgressChanged = delegate { };

        /// <summary>初始化资源回调</summary>
        public event EventHandler<LoadResourceCompletedEventArgs> InitResourceCompleted = delegate { };
        
       
        /// <summary>
        /// 初始化工作环境
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="localPrefix"></param>
        /// <param name="remotePrefix"></param>
        /// <param name="type"></param>
        public void InitEnv(string ip, int port, RemoteType type, string localPrefix, string remotePrefix)
        {
            _config.RemoteIP = ip;
            _config.RemotePort = port;
            _config.RemoteType = type;
            _config.RemotePath = remotePrefix;
            _config.LocalPath = localPrefix;
        }

        /// <summary>
        /// 加载版本控制文件
        /// </summary>
        /// <param name="versionFile"></param>
        public void InitResourceAsync(string versionFile)
        {
            _config.VersionFile = versionFile;
            LoadResourceAsync(_config.VersionFile, VERSIONFILE_LOAD);
        }

        public void InitResourceAsync()
        {
            LoadResourceAsync(_config.VersionFile, VERSIONFILE_LOAD);
        }

        /// <summary>
        /// 请求资源
        /// </summary>
        /// <param name="resource"></param>
        /// <param name="userData"></param>
        /// <returns></returns>
        public void LoadResourceAsync(string resourceName, object userState)
        {
            _operation = AsyncOperationManager.CreateOperation(null);

            /// 不重复请求
            ResourceStatus status = _resources[resourceName];
            if (status == ResourceStatus.Loading || status == ResourceStatus.Prepare)
            {
                return;
            }

            /// 如果版本控制文件没有被加载
            if (!_ver.IsLoaded)
            {
                if (userState == VERSIONFILE_LOAD)
                {
                    _resources.Add(resourceName, ResourceStatus.Loading, userState);
                    Download(resourceName, userState);
                    return ;
                }
                return ;
            }

            /// 已经请求过的资源或者本地资源本身就是最新的，直接返回
            if (status == ResourceStatus.Loaded && _ver.VerifyVersion(resourceName))
             {
                 OnDownloadDone(null, new LoadResourceCompletedEventArgs(null, false, userState, resourceName));
                 return ;
             }


            if (_resources.LoadingCount > _config.MaxConcurrentTasksNumber)
            {
                _resources.Add(resourceName, ResourceStatus.Prepare, userState);
            }
            else
            {
                _resources.Add(resourceName, ResourceStatus.Loading, userState);
                Download(resourceName, userState);
            }

            return ;
        }

        public void CancelAsync()
        {
            _downloader.CancelAsync();
        }

        /// <summary>
        /// 下载资源
        /// </summary>
        /// <param name="resourceName"></param>
        /// <param name="userState"></param>
        private void Download(string resourceName, object userState)
        {
            _downloader = new Downloader();
            _downloader.DownloadCompleted += OnDownloadDone;
            _downloader.DownloadProgressChanged += OnDownloadProcessChanged;
            _downloader.DownloadAsync(resourceName, userState, _config);
        }

        private void OnDownloadProcessChanged(object o, LoadResourceProgressChangedEventArgs args)
        {
            EventHandler<LoadResourceProgressChangedEventArgs> local = null;
            {
                local = LoadProgressChanged;
            }

            if (null != local)
            {
                _operation.Post(d => local(this, args), null);
            }
        }

        /// <summary>
        /// 下载资源完毕
        /// </summary>
        /// <param name="o"></param>
        /// <param name="args"></param>
        private void OnDownloadDone(object o, LoadResourceCompletedEventArgs args)
        {
            Exception error = args.Error;
            string filename = _config.LocalPath + args.ResourceName;
            if (error == null)
            {
                if (args.UserState == VERSIONFILE_LOAD)
                {
                    try
                    {
                        _ver.LoadVersionFile(filename);
                    }
                    catch (System.Exception ex)
                    {
                        error = ex;
                    }
                }
            }

            if (error == null)
            {
                _resources[args.ResourceName] = ResourceStatus.Loaded;
            }
            else
            {
                _resources.Remove(args.ResourceName);
            }

            string nextResource;
            object nextUserState;
            if (_resources.Random(args.ResourceName, out nextResource, out nextUserState))
            {
                Download(nextResource, nextUserState);
            }
            
            EventHandler<LoadResourceCompletedEventArgs> local = null;
            if (args.UserState == VERSIONFILE_LOAD)
            {
                local = InitResourceCompleted;
            }
            else
            {
                local = LoadResourceCompleted;
            }
          
            if (null != local)
            {
                _operation.Post(d => local(this, new LoadResourceCompletedEventArgs(error, args.Cancelled, args.UserState, filename)), null);
            }
        }

        private VersionController _ver = new VersionController();


        private ResourceCollection _resources = new ResourceCollection();
        private Config _config = Config.Instance;
 
        private AsyncOperation _operation = null;
        private Downloader _downloader;
    }

}
